using System;
using Unity.Burst;
using UnityEngine.Playables;
using static DA.AnimGraph.NodeLink;

namespace DA.AnimGraph {
#if UNITY_EDITOR
    [System.Diagnostics.DebuggerTypeProxy(typeof(NodeVirtualTableDebugView))]
#endif
    [BurstCompile]
    public unsafe struct NodeVirtualTable {
        // Init 非必须，按override方式调用
        // internal delegate void InitDelegate(in void* node, in InitContext i);
        internal void* InitFunctionPtr;
        internal InitDelegate InitFunction {
            set { InitFunctionPtr = BurstCompiler.CompileFunctionPointer(value).Value.ToPointer(); }
        }
        internal delegate* unmanaged[Cdecl]<in void*, in InitContext, void> InitFunctionCall {
            get => (delegate* unmanaged[Cdecl]<in void*, in InitContext, void>)InitFunctionPtr;
        }

        // BuildPlayableGraph 必须
        internal void* buildPlayableGraphFunctionPtr;
        internal delegate* managed<in void*, in NodeLink*, in PlayableGraph, in BuildContext, Playable> BuildPlayableGraphFunction {
            get => (delegate* managed<in void*, in NodeLink*, in PlayableGraph, in BuildContext, Playable>)buildPlayableGraphFunctionPtr;
            set => buildPlayableGraphFunctionPtr = value;
        }

        // Evaluate 必须
        // internal delegate void EvaluateDelegate(in void* node, bool onEnter, in EvaluateContext e, in GraphContext g, ref UpstreamData u, ref ScopeContext s);
        internal void* EvaluateFunctionPtr;
        internal EvaluateDelegate EvaluateFunction {
            set { EvaluateFunctionPtr = BurstCompiler.CompileFunctionPointer(value).Value.ToPointer(); }
        }
        internal delegate* unmanaged[Cdecl]<in void*, bool, in EvaluateContext, in GraphContext, ref UpstreamData, ref ScopeContext, void> EvaluateFunctionCall {
            get => (delegate* unmanaged[Cdecl]<in void*, bool, in EvaluateContext, in GraphContext, ref UpstreamData, ref ScopeContext, void>)EvaluateFunctionPtr;
        }

        // OnExit 非必须，按override方式调用
        // internal delegate void OnExitDelegate(in void* node, ref UpstreamData u);
        internal void* OnExitFunctionPtr;
        internal OnExitDelegate OnExitFunction {
            set { OnExitFunctionPtr = BurstCompiler.CompileFunctionPointer(value).Value.ToPointer(); }
        }
        internal delegate* unmanaged[Cdecl]<in void*, ref UpstreamData, void> OnExitFunctionCall {
            get => (delegate* unmanaged[Cdecl]<in void*, ref UpstreamData, void>)OnExitFunctionPtr;
        }

        // PostEvaluate 非必须，按override方式调用
        // internal delegate void PostEvaluateDelegate(in void* node, in EvaluateContext e, in GraphContext g, ref UpstreamData u, ref PostScopeContext p);
        internal void* PostEvaluateFunctionPtr;
        internal PostEvaluateDelegate PostEvaluateFunction {
            set { PostEvaluateFunctionPtr = BurstCompiler.CompileFunctionPointer(value).Value.ToPointer(); }
        }
        internal delegate* unmanaged[Cdecl]<in void*, in EvaluateContext, in GraphContext, ref UpstreamData, ref PostScopeContext, void> PostEvaluateFunctionCall {
            get => (delegate* unmanaged[Cdecl]<in void*, in EvaluateContext, in GraphContext, ref UpstreamData, ref PostScopeContext, void>)PostEvaluateFunctionPtr;
        }

        // Apply 非必须，按override方式调用
        // internal delegate void ApplyDelegate(in void* node);
        internal void* ApplyFunctionPtr;
        internal ApplyDelegate ApplyFunction {
            set { ApplyFunctionPtr = BurstCompiler.CompileFunctionPointer(value).Value.ToPointer(); }
        }
        internal delegate* unmanaged[Cdecl]<in void*, void> ApplyFunctionCall {
            get => (delegate* unmanaged[Cdecl]<in void*, void>)ApplyFunctionPtr;
        }

        // Dispose 非必须，按event方式调用，返回true会统一处理子节点调用
        // internal delegate bool DisposeDelegate(in void* node);
        internal void* DisposeFunctionPtr;
        internal DisposeDelegate DisposeFunction {
            set { DisposeFunctionPtr = BurstCompiler.CompileFunctionPointer(value).Value.ToPointer(); }
        }
        internal delegate* unmanaged[Cdecl]<in void*, bool> DisposeFunctionCall {
            get => (delegate* unmanaged[Cdecl]<in void*, bool>)DisposeFunctionPtr;
        }

        // GetTimeState 非必须，采样节点不用实现。获取子节点的 TimeState（传递进度），决定传递哪个子节点
        internal void* GetTimeStateFunctionPtr;
        internal GetTimeStateDelegate GetTimeStateFunction {
            set { GetTimeStateFunctionPtr = BurstCompiler.CompileFunctionPointer(value).Value.ToPointer(); }
        }
        internal delegate* unmanaged[Cdecl]<in void*, IntPtr> GetTimeStateFunctionCall {
            get => (delegate* unmanaged[Cdecl]<in void*, IntPtr>)GetTimeStateFunctionPtr;
        }

#if UNITY_EDITOR
        internal class NodeVirtualTableDebugView {
            private NodeVirtualTable target;
            public void* InitFunctionPtr => target.InitFunctionPtr;
            public void* buildPlayableGraphFunctionPtr => target.buildPlayableGraphFunctionPtr;
            public void* EvaluateFunctionPtr => target.EvaluateFunctionPtr;
            public void* OnExitFunctionPtr => target.OnExitFunctionPtr;
            public void* PostEvaluateFunctionPtr => target.PostEvaluateFunctionPtr;
            public void* ApplyFunctionPtr => target.ApplyFunctionPtr;
            public void* DisposeFunctionPtr => target.DisposeFunctionPtr;

            public void* GetTimeStateFunctionPtr => target.GetTimeStateFunctionPtr;

            public NodeVirtualTableDebugView(NodeVirtualTable target) {
                this.target = target;
            }
        }
#endif
    }
}
